package com.tools.cleanmaster.ui.view.oversroll;

import android.view.MotionEvent;
import android.view.View;
import android.widget.ListView;

import com.tools.cleanmaster.CleanApplication;
import com.tools.cleanmaster.R;
import com.tools.cleanmaster.utils.Reflections;

import java.lang.reflect.Field;

/**
 * Created by apolunor on 15/12/10.
 */
public class OverScrollListViewTool extends AbsOverScrollTool {

    private static final int REBOUND_STEP = 2;
    private static final int REBOUND_DELAY = 16;

    private ListView mTarget;

    // 从2.0到6.0，listview 通过这两个变量控制长按事件
    private static final String FIELD_mPendingCheckForLongPress = "mPendingCheckForLongPress";
    private static final String FIELD_mPendingCheckForTap = "mPendingCheckForTap";

    private int mMotionPosition;
    private boolean mIsCancelPressIfNeed = false;
    private Field mPendingCheckForLongPressField;
    private Field mPendingCheckForTapField;

    private int mStep = REBOUND_STEP;


    private class ReboundRunnable implements Runnable {

        private int mDistance;
        private boolean mIsDown = false;

        ReboundRunnable(int distance) {
            mDistance = distance;
            mIsDown = (mDistance > 0);
        }

        @Override
        public void run() {
            mDistance += (mIsDown ? -mStep : mStep);
            mTarget.scrollTo(0, mDistance);
            if ((mIsDown && mDistance <= 0) || (!mIsDown && mDistance >= 0)) {
                mTarget.scrollTo(0, 0);
                mDistance = 0;
                return;
            }
            mStep += REBOUND_STEP;
            mTarget.postDelayed(this, REBOUND_DELAY);
        }
    }

    public OverScrollListViewTool(ListView listView) {
        this(listView, false);
    }

    public OverScrollListViewTool(ListView listView, boolean isCancelPressIfNeed) {
        MAX_DISTANCE = (int) CleanApplication.getInstance().getResources().getDimension(R.dimen.over_scroll_list_view_max_distance);
        mTarget = listView;
        mIsCancelPressIfNeed = isCancelPressIfNeed;
        if (mIsCancelPressIfNeed) {
            mPendingCheckForLongPressField
                    = Reflections.findFieldNoThrow(mTarget.getClass(), FIELD_mPendingCheckForLongPress);
            mPendingCheckForTapField
                    = Reflections.findFieldNoThrow(mTarget.getClass(), FIELD_mPendingCheckForTap);
        }
    }

    @Override
    public void scroll(int delta) {
        mTarget.scrollTo(0, delta);
    }

    @Override
    public void rebound(int delta) {
        mTarget.post(new ReboundRunnable(delta));
    }

    @Override
    public boolean handleTouchEventDown(MotionEvent event) {
        final int x = (int) event.getX();
        final int y = (int) event.getY();
        mMotionPosition = mTarget.pointToPosition(x, y);
        return super.handleTouchEventDown(event);
    }

    @Override
    public boolean handleTouchEventMove(MotionEvent event) {
        boolean consume = super.handleTouchEventMove(event);
        if (consume) {
            cancelPressIfNeed();
        }
        return consume;
    }

    @Override
    public boolean handleTouchEventUp(MotionEvent event) {
        cancelPressIfNeed();
        return super.handleTouchEventUp(event);
    }

    @Override
    public boolean handleTouchEventCancel(MotionEvent event) {
        cancelPressIfNeed();
        return super.handleTouchEventCancel(event);
    }

    @Override
    protected void reset() {
        super.reset();
    }

    @Override
    protected boolean isCanPullDown() {
        if (mTarget.getFirstVisiblePosition() == 0 && mTarget.getChildCount() > 0) {
            final View firstVisibleChild = mTarget.getChildAt(0);
            if (firstVisibleChild != null) {
                return firstVisibleChild.getTop() >= mTarget.getPaddingTop();
            }
        }
        return false;
    }

    @Override
    protected boolean isCanPullUp() {
        if ((mTarget.getLastVisiblePosition() == mTarget.getCount() - 1) && mTarget.getChildCount() > 0) {
            final View lastVisibleChild = mTarget.getChildAt(mTarget.getChildCount() - 1);
            if (lastVisibleChild != null) {
                return lastVisibleChild.getBottom() <= (mTarget.getHeight() - mTarget.getPaddingBottom());
            }
        }
        return false;
    }

    protected void cancelPressIfNeed() {
        if (mIsCancelPressIfNeed) {
            mTarget.setPressed(false);
            final int index = mMotionPosition - mTarget.getFirstVisiblePosition();
            if (index >= 0 && index < mTarget.getChildCount()) {
                final View motionView = mTarget.getChildAt(mMotionPosition - mTarget.getFirstVisiblePosition());
                if (motionView != null) {
                    motionView.setPressed(false);
                }
            }
            Object action = Reflections.getValueNoThrow(mPendingCheckForTapField, mTarget);
            if (action instanceof Runnable) {
                mTarget.removeCallbacks((Runnable) action);
            }
            action = Reflections.getValueNoThrow(mPendingCheckForLongPressField, mTarget);
            if (action instanceof Runnable) {
                mTarget.removeCallbacks((Runnable) action);
            }
        }
    }
}
